using System;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Sockets;
using wicpowerTcpTool.Network;
using System.Net;
using System.Xml;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace wicpowerTcpTool.Models
{
    /// <summary>
    /// 转发组类，管理一对TCP服务器之间的数据转发
    /// </summary>
    /// <remarks>
    /// 功能：
    /// 1. 管理两个TCP服务器实例
    /// 2. 实现双向数据转发
    /// 3. 提供状态监控和事件通知
    /// 4. 支持密令验证机制
    /// 
    /// 设计特点：
    /// - 实现IDisposable接口
    /// - 实现INotifyPropertyChanged接口
    /// - 线程安全设计
    /// </remarks>
    public class ForwardGroup : IDisposable, INotifyPropertyChanged
    {
        /// <summary>
        /// 设备端服务器实例
        /// </summary>
        private TcpServer server1;
        
        /// <summary>
        /// 客户端服务器实例
        /// </summary>
        private TcpServer server2;
        
        /// <summary>
        /// 对象是否已释放标志
        /// </summary>
        private bool isDisposed;
        
        /// <summary>
        /// 服务器1监听IP地址
        /// </summary>
        private IPAddress listenIP1;
        
        /// <summary>
        /// 服务器2监听IP地址
        /// </summary>
        private IPAddress listenIP2;
        
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        private readonly int port1;
        private readonly int port2;

        /// <summary>
        /// 转发组ID
        /// 注意：设置为可写以支持配置加载时设置ID
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// 监听端口1
        /// </summary>
        public int Port1 => port1;

        /// <summary>
        /// 转发端口2
        /// </summary>
        public int Port2 => port2;

        /// <summary>
        /// 备注信息
        /// </summary>
        public string Remark { get; }
        private string _authToken;
        public string AuthToken 
        {
            get => _authToken;
            set
            {
                if (_authToken != value)
                {
                    _authToken = value;
                    OnPropertyChanged();
                    // 只对server2(客户端连接端)设置密令验证
                    if(server2 != null) server2.SetAuthToken(value);
                }
            }
        }

        /// <summary>
        /// 服务器1的运行状态
        /// </summary>
        public bool IsServer1Running => server1?.IsRunning ?? false;

        /// <summary>
        /// 服务器2的运行状态
        /// </summary>
        public bool IsServer2Running => server2?.IsRunning ?? false;

        /// <summary>
        /// 服务器1的客户端连接状态
        /// </summary>
        public bool IsClient1Connected => server1?.IsClientConnected ?? false;

        /// <summary>
        /// 服务器2的客户端连接状态
        /// </summary>
        public bool IsClient2Connected => server2?.IsClientConnected ?? false;

        // 事件
        public event EventHandler<bool> Server1StatusChanged;
        public event EventHandler<bool> Server2StatusChanged;
        public event EventHandler<bool> Client1StatusChanged;
        public event EventHandler<bool> Client2StatusChanged;
        public event EventHandler<Exception> ErrorOccurred;
        public event EventHandler DataTransferred;

        /// <summary>
        /// 无参构造函数(用于序列化)
        /// </summary>
        public ForwardGroup() : this(0, 0, 0, "Default")
        {
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="id">转发组ID</param>
        /// <param name="port1">监听端口</param>
        /// <param name="port2">转发端口</param>
        /// <param name="remark">备注信息</param>
        /// <param name="authToken">验证令牌</param>
        /// <param name="listenIP1">服务器1监听IP</param>
        /// <param name="listenIP2">服务器2监听IP</param>
        /// <remarks>
        /// 初始化流程：
        /// 1. 设置基本参数
        /// 2. 创建服务器实例
        /// 3. 设置验证令牌
        /// 
        /// 设计说明：
        /// - listenIP2默认为listenIP1的值
        /// - 验证令牌在服务器创建后设置
        /// - 记录初始化日志
        /// </remarks>
        public ForwardGroup(int id, int port1, int port2, string remark, 
                          string authToken = "",
                          IPAddress listenIP1 = null, IPAddress listenIP2 = null)
        {
            Id = id;
            this.port1 = port1;
            this.port2 = port2;
            Remark = remark;
            this.listenIP1 = listenIP1 ?? IPAddress.Any;
            this.listenIP2 = listenIP2 ?? this.listenIP1;
            
            // 创建初始服务器实例
            CreateServers();
            
            // 设置密令（必须在CreateServers之后）
            AuthToken = authToken;
            Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] ForwardGroup初始化完成");
            Console.WriteLine($"端口1: {port1}, 端口2: {port2}");
            Console.WriteLine($"密令设置: {authToken}");
        }

        /// <summary>
        /// 创建服务器实例
        /// </summary>
        /// <summary>
        /// 创建服务器实例并初始化事件处理
        /// </summary>
        /// <remarks>
        /// 执行流程：
        /// 1. 清理旧服务器实例
        /// 2. 创建新服务器实例
        ///   - server1(设备端): 禁用验证
        ///   - server2(客户端): 启用验证
        /// 3. 设置验证令牌
        /// 4. 绑定事件处理
        /// 
        /// 事件绑定：
        /// - 连接状态变化事件
        /// - 服务器状态变化事件
        /// - 数据接收事件
        /// - 错误发生事件
        /// </remarks>
        private void CreateServers()
        {
            // 清理旧的服务器实例
            server1?.Dispose();
            server2?.Dispose();

            // 创建服务器实例
            // server1(设备端) - 禁用验证
            server1 = new TcpServer(port1, listenIP1, false);
            // server2(客户端) - 启用验证
            server2 = new TcpServer(port2, listenIP2, true);
            server2.SetAuthToken(_authToken); // 立即设置密令
            Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 服务器初始化完成");
            Console.WriteLine($"端口{port1}(设备端): 验证已禁用");
            Console.WriteLine($"端口{port2}(客户端): 验证已启用");

            // 绑定事件处理
            server1.ConnectionStatusChanged += (s, connected) => Client1StatusChanged?.Invoke(this, connected);
            server2.ConnectionStatusChanged += (s, connected) => Client2StatusChanged?.Invoke(this, connected);
            
            server1.ServerStatusChanged += (s, status) => Server1StatusChanged?.Invoke(this, status);
            server2.ServerStatusChanged += (s, status) => Server2StatusChanged?.Invoke(this, status);
            
            // 监听端口1(设备端) -> 转发端口2(客户端)
            server1.DataReceived += async (s, data) =>
            {
                try 
                {
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 转发数据: 端口{Port1} -> 端口{Port2}, 长度: {data.Length}");
                    if (server2.IsRunning && server2.IsClientConnected)
                    {
                        await server2.SendDataAsync(data);
                        DataTransferred?.Invoke(this, EventArgs.Empty);
                    }
                    else
                    {
                        Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 转发失败: 端口{Port2}未就绪");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 监听端口转发异常: {ex.Message}");
                    ErrorOccurred?.Invoke(this, ex);
                }
            };

            // 转发端口2(客户端) -> 监听端口1(设备端)
            server2.DataReceived += async (s, data) =>
            {
                try 
                {
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 收到客户端数据: 端口{Port2}, 长度: {data.Length}");
                    Console.WriteLine($"数据内容(HEX): {BitConverter.ToString(data)}");
                    
                    // 1. 检查设备端(端口1)是否在线
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 检查设备端状态: 运行={server1.IsRunning}, 连接={server1.IsClientConnected}");
                    if (!server1.IsRunning || !server1.IsClientConnected)
                    {
                        Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 转发拒绝: 设备端(端口{Port1})未连接");
                        return;
                    }

                    // 2. 执行转发
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 正在转发数据: 端口{Port2} -> 端口{Port1}");
                    await server1.SendDataAsync(data);
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 转发完成: 端口{Port2} -> 端口{Port1}, 长度: {data.Length}");
                    DataTransferred?.Invoke(this, EventArgs.Empty);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 转发异常:");
                    Console.WriteLine($"异常类型: {ex.GetType().Name}");
                    Console.WriteLine($"异常消息: {ex.Message}");
                    Console.WriteLine($"堆栈跟踪: {ex.StackTrace}");
                    ErrorOccurred?.Invoke(this, ex);
                }
            };

            server1.ErrorOccurred += (s, ex) => ErrorOccurred?.Invoke(this, ex);
            server2.ErrorOccurred += (s, ex) => ErrorOccurred?.Invoke(this, ex);
        }

        /// <summary>
        /// 更新监听IP地址 (兼容旧版本)
        /// </summary>
        public void UpdateListenIP(IPAddress newIP)
        {
            UpdateListenIPs(newIP, newIP);
        }

        /// <summary>
        /// 更新监听IP地址
        /// </summary>
        public void UpdateListenIPs(IPAddress newIP1, IPAddress newIP2 = null)
        {
            if (IsServer1Running || IsServer2Running)
            {
                throw new InvalidOperationException("无法在服务运行时更改监听IP");
            }
            listenIP1 = newIP1 ?? IPAddress.Any;
            listenIP2 = newIP2 ?? listenIP1;
            CreateServers();  // 使用新IP重新创建服务器实例
        }

        /// <summary>
        /// 启动转发服务
        /// </summary>
        /// <summary>
        /// 启动转发服务
        /// </summary>
        /// <remarks>
        /// 执行流程：
        /// 1. 状态检查
        /// 2. 必要时创建服务器实例
        /// 3. 验证端口可用性
        /// 4. 启动服务器
        /// 
        /// 异常处理：
        /// - 对象已释放时抛出ObjectDisposedException
        /// - 端口被占用时抛出InvalidOperationException
        /// - 其他异常时自动停止服务并重新抛出
        /// </remarks>
        public void Start()
        {
            if (isDisposed)
                throw new ObjectDisposedException(nameof(ForwardGroup));

            try
            {
                // 如果服务器实例不存在，创建新的实例
                if (server1 == null || server2 == null)
                {
                    CreateServers();
                }

                // 确保端口可用 - 更可靠的检测
                if (!IsPortAvailable(port1))
                {
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 端口 {port1} 检测失败");
                    throw new InvalidOperationException($"端口 {port1} 已被占用，请修改配置或关闭占用该端口的程序");
                }
                if (!IsPortAvailable(port2))
                {
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 端口 {port2} 检测失败");
                    throw new InvalidOperationException($"端口 {port2} 已被占用，请修改配置或关闭占用该端口的程序");
                }

                Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 端口检测通过: {port1}/{port2}");
                
                // 启动服务器，不再需要时间间隔
                try
                {
                    server1.Start();
                    server2.Start();
                }
                catch (SocketException ex) when (ex.SocketErrorCode == SocketError.AddressAlreadyInUse)
                {
                    throw new InvalidOperationException($"端口已被占用: {ex.Message}", ex);
                }
            }
            catch (Exception)
            {
                Stop();
                throw;
            }
        }

        /// <summary>
        /// 停止转发服务
        /// </summary>
        public void Stop()
        {
            if (isDisposed)
                return;

            server1?.Stop();
            server2?.Stop();
        }

        /// <summary>
        /// 检查端口是否可用
        /// </summary>
        /// <summary>
        /// 检查端口是否可用
        /// </summary>
        /// <param name="port">要检查的端口号</param>
        /// <returns>是否可用</returns>
        /// <remarks>
        /// 实现原理：
        /// 尝试在指定端口创建TCP监听器
        /// - 成功: 端口可用
        /// - 失败: 端口被占用
        /// 
        /// 资源管理：
        /// - 使用try-finally确保监听器释放
        /// - 静默捕获所有异常
        /// </remarks>
        public static bool IsPortAvailable(int port)
        {
            var listener = new TcpListener(IPAddress.Any, port);
            try
            {
                listener.Start();
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                listener.Stop();
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <remarks>
        /// 释放流程：
        /// 1. 停止服务
        /// 2. 释放服务器实例
        /// 3. 设置释放标志
        /// 
        /// 设计说明：
        /// - 实现IDisposable接口
        /// - 线程安全设计
        /// - 可多次调用
        /// </remarks>
        public void Dispose()
        {
            if (isDisposed)
                return;

            Stop();
            server1?.Dispose();
            server2?.Dispose();
            isDisposed = true;
        }
        /// <summary>
        /// 监听IP地址
        /// </summary>
        [System.Xml.Serialization.XmlElement("ListenIP")]
        public IPAddress ListenIP 
        {
            get { return listenIP1; }
            set 
            {
                if (listenIP1 != value)
                {
                    listenIP1 = value;
                    listenIP2 = value;
                    OnPropertyChanged(nameof(ListenIP));
                }
            }
        }
    }
}